C 调用 Go 生成动态链接库实录

前言

最近在用 C 语言写一个自己的编程语言,准备做成类似易语言的中文语言。其中有将中文文字转为拼音的需求,但是 C 语言中比较难做到,如果要自己实现要做一个比较大的字典,显然不切合实际,正好 Go 语言中有这样的一个库可以做到:github.com/mozillazg/go-pinyin。所以打算用 C 调用 Go 进行实现。

实现过程

Golang 代码

convertPinyin.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
"C"
"unicode"

"github.com/mozillazg/go-pinyin"
)

//export convertPinyin
func convertPinyin(value string) string {
stringSlice := []rune(value)
convertedCode := ""
// Support Chinese words in quotation
quotationFlag := false
for i := 0; i < len(stringSlice); i++ {
ch := string(stringSlice[i])
if ch == "\"" {
quotationFlag = !quotationFlag
convertedCode += ch
continue
} else if quotationFlag == true {
convertedCode += ch
continue
}
if unicode.Is(unicode.Scripts["Han"], stringSlice[i]) {
convertedCode += pinyin.LazyConvert(ch, nil)[0]
} else {
convertedCode += ch
}
}
return convertedCode
}

func main() {
}

这个方法实现了将中文部分转换成拼音字符串返回,下面简单说说遇到的问题。

编译运行以及遇到的问题

我的编译器代码为 ry.c ,首先将 GO 的代码编译成 convertPinyin.soconvertPinyin.h 文件。

1
go build -buildmode=c-shared -o convertPinyin.so convertPinyin.go

在 C 语言的代码中引入:

1
#include "convertPinyin.h"

然后进行编译,最初编译命令如下:

1
gcc -o ry ry.c

这里遇到第一个问题:

1
undefined reference to 'convertPinyin'

出现的原因是链接时缺少相关的库文件,这里有详细解读:“undefined reference to” 问题汇总及解决方法

于是更改命令为:

1
gcc -o ry ry.c convertPinyin.so

成功了。于是我使用 ./ry hello.ry 来运行编译我的 Rylang 语言,出现第二个错误:

1
./ry: error while loading shared libraries: convertPinyin.so: cannot open shared object file: No such file or directory

文件明明存在但是却找不到是由于当前目录并不在查找范围内,因此显示无法找到。解决方法:

1
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

最后的 . 表示把当前目录加入到动态链接库查找的目录中去重新运行成功!

上述方法设置是临时的 另外一种方法:

1
sudo vi /etc/ld.so.conf

添加库路径 如 ./ (表示当前目录)
添加保存后

1
sudo ldconfig

完整的命令如下:

1
2
3
4
go build -buildmode=c-shared -o convertPinyin.so convertPinyin.go
gcc -o ry ry.c convertPinyin.so
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
./ry hello.ry

最后还遇到问题:

1
panic: runtime error: cgo result has Go pointer

应该把 Go 的 string 类型转换成 C 语言的 *C.char 类型。更改 convertPinyin.go 的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
"C"
"unicode"

"github.com/mozillazg/go-pinyin"
)

//export convertPinyin
func convertPinyin(value string) *C.char {
stringSlice := []rune(value)
convertedCode := ""
// Support Chinese words in quotation
quotationFlag := false
for i := 0; i < len(stringSlice); i++ {
ch := string(stringSlice[i])
if ch == "\"" {
quotationFlag = !quotationFlag
convertedCode += ch
continue
} else if quotationFlag == true {
convertedCode += ch
continue
}
if unicode.Is(unicode.Scripts["Han"], stringSlice[i]) {
convertedCode += pinyin.LazyConvert(ch, nil)[0]
} else {
convertedCode += ch
}
}
return C.CString(convertedCode)
}

func main() {
}

还遇到其他问题:

  • 提示 can't load package: package .: build constraints exclude all Go files in ,需要先设置 go envset CGO_ENABLED=1
  • 有一种情况需要在 32 位情况下编译,修改 GOARCH:set GOARCH=386

这里有个不错的文章:https://ejin66.github.io/2018/09/15/go-to-so-android.html

0%